package com.tian.service.impl.pay;
import java.util.Date;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.tian.common.enums.PayStatusEnum;
import com.tian.common.enums.RetryMessageTypeEnum;
import com.tian.common.enums.UserBalanceChangeTypeEnum;
import com.tian.common.util.*;
import com.tian.dto.pay.ChargePayOrderCount4ManagementRespDto;
import com.tian.dto.user.ChargeUserLoginResDto;
import com.tian.dto.pay.PayOrderQueryReqDto;
import com.tian.dto.pay.PayOrderQueryRespDto;
import com.tian.entity.ChargePayOrder;
import com.tian.entity.UserBalance;
import com.tian.entity.UserBalanceChangeRecord;
import com.tian.mapper.ChargePayOrderMapper;
import com.tian.mapper.UserBalanceChangeRecordMapper;
import com.tian.mapper.UserBalanceMapper;
import com.tian.mq.message.MessageReqIdPrefixConstant;
import com.tian.mq.message.UserBalanceDecrMessage;
import com.tian.mq.producer.BaseProducer;
import com.tian.service.pay.PayOrderQueryService;
import com.tian.service.pay.UserBalanceService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * {@code @description:} 我的充值订单信息查询服务实现类
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-12-03 9:50
 * {@code @version:} 1.0
 */
@Service
public class PayOrderQueryServiceImpl implements PayOrderQueryService {
    @Resource
    private ChargePayOrderMapper chargePayOrderMapper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private UserBalanceMapper userBalanceMapper;
    @Resource
    private UserBalanceChangeRecordMapper userBalanceChangeRecordMapper;
    @Resource
    private RedissonClient redissonClient;

    @Override
    public CommonResult<PageResult<List<PayOrderQueryRespDto>>> query(PayOrderQueryReqDto payOrderQueryReqDto) {
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        payOrderQueryReqDto.setUserId(user.getId());
        return getResultCommonResult(payOrderQueryReqDto);
    }

    @Override
    public CommonResult<PageResult<List<PayOrderQueryRespDto>>> queryManagement(PayOrderQueryReqDto payOrderQueryReqDto) {
        return getResultCommonResult(payOrderQueryReqDto);
    }

    @Override
    public CommonResult<ChargePayOrderCount4ManagementRespDto> count4Management() {
        long payOrderCountTimes = chargePayOrderMapper.countTimes4Total();
        long payOrderFailCountTimes = chargePayOrderMapper.countTimes4Fail();
        BigDecimal payOrderCountAmount = chargePayOrderMapper.countAmount4Total();
        BigDecimal payOrderFailCountAmount = chargePayOrderMapper.countAmount4Fail();

        ChargePayOrderCount4ManagementRespDto chargePayOrderCount4ManagementRespDto = new ChargePayOrderCount4ManagementRespDto();
        chargePayOrderCount4ManagementRespDto.setPayOrderCountTimes(payOrderCountTimes);
        chargePayOrderCount4ManagementRespDto.setPayOrderFailCountTimes(payOrderFailCountTimes);
        chargePayOrderCount4ManagementRespDto.setPayOrderCountAmount(payOrderCountAmount.setScale(2, RoundingMode.HALF_UP) + "元");
        chargePayOrderCount4ManagementRespDto.setPayOrderFailCountAmount(payOrderFailCountAmount == null ? BigDecimal.ZERO.toString() : payOrderFailCountAmount.setScale(2, RoundingMode.HALF_UP) + "元");
        return CommonResult.success(chargePayOrderCount4ManagementRespDto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommonResult<String> refund(Long id) {

        ChargePayOrder chargePayOrder = chargePayOrderMapper.selectByPrimaryKey(id);

        /*
         * 根据支付订单号和支付渠道退款  原路退回
         * 1. 调用支付接口退款逻辑
         * 2. 退款成功后修改支付订单状态为退款成功
         * 3. 发送消息到用户余额消息队列
         * 4. 返回成功信息
         *
         * 注意：这里是直接退款了，真实项目中是需要调用支付平台的退扣借款，支付平台退款接口返回退款成功后，我们再修改支付订单状态为退款成功
         */
        chargePayOrder.setPayStatus(PayStatusEnum.REFUND.getCode());
        Long userId = chargePayOrder.getUserId();
        RLock lock = redissonClient.getLock(RedisConstantPre.USER_INFO_ID_LOCK_PRE + userId);
        lock.lock();
        try {
            UserBalance userBalance = userBalanceMapper.selectByUserId(userId);
            BigDecimal balance = userBalance.getBalance().subtract(userBalance.getFreezeBalance());
            if(balance.compareTo(chargePayOrder.getAmount()) < 0){
                return CommonResult.failed("余额不足，请保证账户余额充足");
            }

            UserBalanceChangeRecord userBalanceChangeRecord = new UserBalanceChangeRecord();
            userBalanceChangeRecord.setUserId(userId);
            userBalanceChangeRecord.setOrderNo(chargePayOrder.getOrderNo());
            userBalanceChangeRecord.setChangeType(UserBalanceChangeTypeEnum.USER_REFUND.getType());
            userBalanceChangeRecord.setBeforeBalance(userBalance.getBalance());
            userBalanceChangeRecord.setChangeBalance(chargePayOrder.getAmount());
            userBalanceChangeRecord.setAfterBalance(userBalance.getBalance().subtract(chargePayOrder.getAmount()));
            userBalanceChangeRecord.setCreateTime(new Date());
            userBalanceChangeRecord.setRemark("用户充值退款");
            userBalance.setBalance(userBalance.getBalance().subtract(chargePayOrder.getAmount()));
            userBalanceMapper.updateByPrimaryKey(userBalance);
            userBalanceChangeRecordMapper.insert(userBalanceChangeRecord);

        }finally {
            lock.unlock();
        }
        chargePayOrderMapper.updateByPrimaryKey(chargePayOrder);

//        UserBalanceDecrMessage userBalanceDecrMessage = new UserBalanceDecrMessage();
//        userBalanceDecrMessage.setUserId(userId);
//        userBalanceDecrMessage.setChangeBalance(chargePayOrder.getAmount());
//        userBalanceDecrMessage.setChangeType(UserBalanceChangeTypeEnum.USER_REFUND.getType());
//        userBalanceDecrMessage.setIsFreeze(false);
//        userBalanceDecrMessage.setRemark("用户退款");
//        userBalanceDecrMessage.setReqId(MessageReqIdPrefixConstant.USER_REFUND_DEDUCT_REQ + UUID.randomUUID() + DateUtils.formatDefaultDateMs());

        // 发送消息到用户余额消息队列
//        baseProducer.send(JSON.toJSONString(userBalanceDecrMessage),RabbitMQConstant.USER_BALANCE_DECR_EXCHANGE, RabbitMQConstant.USER_BALANCE_DECR_ROUTING_KEY, RetryMessageTypeEnum.USER_REFUND.getType());
        return CommonResult.success("退款成功");
    }

    private CommonResult<PageResult<List<PayOrderQueryRespDto>>> getResultCommonResult(PayOrderQueryReqDto payOrderQueryReqDto) {
        Page<ChargePayOrder> page = PageHelper.startPage(payOrderQueryReqDto.getCurrentPage(), payOrderQueryReqDto.getPageSize());
        List<ChargePayOrder> chargePayOrders = chargePayOrderMapper.selectByUserIdAndStatus(payOrderQueryReqDto);
        List<PayOrderQueryRespDto> payOrderQueryRespDtoList = new ArrayList<>();
        chargePayOrders.forEach(chargePayOrder -> {
            PayOrderQueryRespDto payOrderQueryRespDto = new PayOrderQueryRespDto();
            payOrderQueryRespDto.setId(chargePayOrder.getId());
            payOrderQueryRespDto.setOrderNo(chargePayOrder.getOrderNo());
            payOrderQueryRespDto.setActualAmount(chargePayOrder.getAmount().toString());
            payOrderQueryRespDto.setTotalAmount(chargePayOrder.getAmount().add(chargePayOrder.getDiscountAmount()).toString());
            payOrderQueryRespDto.setPayTime(DateUtils.format(chargePayOrder.getUpdateTime(), DateUtils.FORMAT_SECOND));
            payOrderQueryRespDto.setPayStatus(chargePayOrder.getPayStatus());
            payOrderQueryRespDto.setChannel(chargePayOrder.getChannel());
            payOrderQueryRespDtoList.add(payOrderQueryRespDto);
        });
        PageResult<List<PayOrderQueryRespDto>> pageResult = PageResult.setData((int) page.getTotal(), payOrderQueryReqDto.getPageSize(),
                page.getPages(), payOrderQueryReqDto.getCurrentPage(), payOrderQueryRespDtoList);
        return CommonResult.success(pageResult);
    }
}
